home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue42 / opengl / glViewFr.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-10-29  |  19.6 KB  |  604 lines

  1. unit glViewFr;
  2. (*
  3. *********************************************************************
  4.     Unit             glViewFrame
  5.     Written by       T. Beattie
  6.     Created          22/5/98
  7.     Last updated     22/5/98
  8. *********************************************************************
  9.  
  10.   Defines a TViewFrame object:
  11.   Fields
  12.     fViewer(x,y,z)    position of viewer
  13.     fLookAt(x,y,z)    position being viewed
  14.     fUpVect(x,y,z)    vector defining up direction
  15.   Methods
  16.     RotateAboutViewer(HorAng,VerAng)
  17.     RotateAboutLookAt(HorAng,VerAng)
  18.     RotateUpVector(xRot,yRot)
  19.     AdvanceToLookAt(Dist)   {and rotate HorAng as well?}
  20.     FlyBy(Dist{Speed},RollAng,PitchAng)
  21.  
  22.   All methods return a boolean result to indicate success.
  23.   All rotation angles are relative, horizontal angles are anti-clockwise
  24.   positive, vertical angles are up positive.
  25.   Movement is described by moving fViewer on a sphere centred on
  26.   fLookAt.
  27.  
  28.   Polar coordinates:
  29.     r     = distance from origin (>0)
  30.     theta = horizontal bearing anti-clockwise from x-axis
  31.     phi   = vertical bearing, 0=horizontal, up=positive, abs(ph)<=90
  32. *)
  33.  
  34. interface
  35.  
  36. uses
  37.   glFuncs;
  38.  
  39. type
  40.  
  41.   TViewFrame = class(tObject)
  42.   protected
  43.     fViewer,                //position of viewer
  44.     fLookAt,                //position being viewed
  45.     fUpVect,                //vector defining up direction
  46.     fLeftEye,               //left eye position
  47.     fRightEye,              //Right eye position
  48.     fOrigin: tGLPoint;    //Store original
  49.     fPerspective          : Boolean;
  50.     fHeadLight            : tGLLight;
  51.     fRange,
  52.     fViewAngle,
  53.     fScreenZ              : Double;
  54.     fScale                : Double;
  55.     fXRadius,
  56.     fYradius,
  57.     fZRadius               : Double;
  58.  
  59.     Procedure SetUpEyePositions;
  60.     Procedure SetViewerPos(aVal:tGLPoint);
  61.   //viewer doesn't own the headlight, it is supplied by the tGLLightWindow if
  62.     Procedure SetXRadius(aVal:Double);
  63.     Procedure SetYRadius(aVal:Double);
  64.     Procedure SetZRadius(aVal:Double);
  65.   public
  66.  
  67.     constructor Create;
  68.     function Duplicate: TViewFrame;
  69.     function RotateAboutViewer(HorAng,VerAng: single): boolean;
  70.     function RotateAboutLookAt(HorAng,VerAng: single): boolean;
  71.     function RotateUpVector(Ang: single): boolean;
  72.     function AdvanceToLookAt(Dist: single): boolean;
  73.     function FlyBy(Speed,RollAng,PitchAng: single): boolean;
  74.     procedure MovePosition(DeltaX,DeltaY,DeltaZ: single);
  75.     procedure MoveFrame(DeltaX,DeltaY,DeltaZ: single);
  76.     procedure SetViewer3s(x,y,z: single);
  77.     procedure SetLookAt3s(x,y,z: single);
  78.     procedure SetUpVector3s(x,y,z: single);
  79.     Procedure SetScale(aVal:Double);
  80.   //jh mod
  81.     procedure SetViewer3d(x,y,z: Double);
  82.     procedure SetLookAt3d(x,y,z: Double);
  83.     procedure SetPerspective(a: boolean);
  84.  
  85.     Procedure SetRange(aVal:Double; AdjustAngle:Boolean);
  86.  // set the range and if adjust then calc a viewangle}
  87.     Procedure SetAngle(aVal:Double; AdjustRange:Boolean);
  88.   //Set the view angle and adjust angle if adjustrange=true}
  89.     Function Distance:Double;
  90.  // distance between position and lookat
  91.     Function  MaxViewPrism(aScale:Single):tGLPoint; //Max X,Y znd Z ocvered in viewport
  92.     // and scale by the scale factor
  93.     Function  MinViewPrism(aScale:Single):tGLPoint; //Min X,Y znd Z ocvered in viewport
  94. // max and min values for view prism
  95.     // and scale by the scale factor
  96.     Function GetBearing:Double;
  97.     Function GetAzimuth:Double;
  98.     Function GetAngleFromVertical:Double;
  99.     Procedure SetViewPoint(aPt:vViewFrom);
  100.     Procedure CopyValuesFrom(aPt:TViewFrame);
  101.     //set the values from the supplied Frame
  102.     Function ShiftLookAt(aDist:Double):Boolean;
  103.     // shift the lookat away from the viewer by the supplied dist
  104.  
  105.     property Scale:Double Read fScale write SetScale;
  106.     property Position: tGLPoint read fViewer write SetViewerPos;
  107.     property LookAt: tGLPoint read fLookAt write fLookAt;
  108.     property UpVector: tGLPoint read fUpVect write fUpVect;
  109.     property Perspective: boolean read fPerspective write SetPerspective;
  110.     Property Headlight:tGLLight read fHeadLight write fHeadLight;
  111.     property AngleFromVert:Double Read GetAngleFromVertical;
  112.     property Bearing:Double Read GetBearing;
  113.     property Azimuth:Double Read GetAzimuth;
  114.     Property Range:Double Read fRange;
  115.     Property ViewAngle:Double Read fViewAngle;
  116.     Property ScreenZ:Double Read fScreenZ write fScreenZ;
  117.     Property XRadius:Double Read fXRadius write SetXRadius;
  118.     Property YRadius:Double Read fYRadius write SetYRadius;
  119.     Property ZRadius:Double Read fZRadius write SetZRadius;
  120.   end;
  121.  
  122.  
  123. const
  124.   DefaultUpVector: tGLPoint = (x:0;y:0;z:1);
  125.   x_vector: tGLPoint = (x:1;y:0;z:0);
  126.   y_vector: tGLPoint = (x:0;y:1;z:0);
  127.   z_vector: tGLPoint = (x:0;y:0;z:1);
  128.  
  129.  // extracted from Tims glViewFr unit
  130.   function AbstractRotateAboutLookAt(var Viewer,LookAt,UpVect:tGLPoint;HorAng,VerAng: single): boolean;
  131.   function AbstractRotateAboutViewer(var Viewer,LookAt,UpVect:tGLPoint;HorAng,VerAng: single): boolean;
  132.  
  133. {*********************************************}
  134.                implementation
  135. {*********************************************}
  136.  
  137. uses
  138.   Math ;
  139.  
  140. const
  141.   pi180 = pi/180;
  142.   small = 0.0001;
  143. (**********************************************************)
  144. function AbstractRotateAboutViewer(var Viewer,LookAt,UpVect:tGLPoint;HorAng,VerAng: single): boolean;
  145. var
  146.   r0, r1: single;
  147.   Pos, View: tGLPoint;
  148. begin
  149.   VerAng:= VerAng*pi180;
  150.   HorAng:= HorAng*pi180;
  151. //assumes up-vector is normalised and maintained perpendicular
  152. //to view-vector.
  153. {subtract origin}
  154.   Pos.x:= LookAt.x - Viewer.x;
  155.   Pos.y:= LookAt.y - Viewer.y;
  156.   Pos.z:= LookAt.z - Viewer.z;
  157.   View:= Pos;      //view_vector
  158. {save radius so move along sphere}
  159.   r0:= sqrt(sqr(Pos.x)+sqr(Pos.y)+sqr(Pos.z));
  160. //y-rotations cause ball to turn in plane of view-vector and up-vector
  161. //so add up-vector to viewer
  162. //Note: dist to move is r * theta (in radians)
  163.   Pos.x:= Pos.x - UpVect.x*VerAng*r0;
  164.   Pos.y:= Pos.y - UpVect.y*VerAng*r0;
  165.   Pos.z:= Pos.z - UpVect.z*VerAng*r0;
  166. //x-rotations cause ball to turn perpendicular to plane of view-vector
  167. //and up-vector so add cross product to viewer
  168. //Note: dist to move is r * theta (in radians) but must divide by
  169. //magnitude of cross-product vectors = r * 1.
  170.   Pos.x:= Pos.x + (View.y*UpVect.z - View.z*UpVect.y)*HorAng;
  171.   Pos.y:= Pos.y + (View.z*UpVect.x - View.x*UpVect.z)*HorAng;
  172.   Pos.z:= Pos.z + (View.x*UpVect.y - View.y*UpVect.x)*HorAng;
  173. {drop point onto sphere}
  174.   r1:= r0/sqrt(sqr(Pos.x)+sqr(Pos.y)+sqr(Pos.z));
  175.   LookAt.x:= Viewer.x + r1*Pos.x;
  176.   LookAt.y:= Viewer.y + r1*Pos.y;
  177.   LookAt.z:= Viewer.z + r1*Pos.z;
  178. {must also push up-vector in same direction as y-rotation so
  179.  add view vector to upvector and normalise}
  180.   UpVect.x:= UpVect.x - View.x*VerAng/r0;
  181.   UpVect.y:= UpVect.y - View.y*VerAng/r0;
  182.   UpVect.z:= UpVect.z - View.z*VerAng/r0;
  183.   r1:= sqrt(sqr(UpVect.x)+sqr(UpVect.y)+sqr(UpVect.z));
  184.   UpVect.x:= UpVect.x/r1;
  185.   UpVect.y:= UpVect.y/r1;
  186.   UpVect.z:= UpVect.z/r1;
  187.   Result:= true;
  188. end;
  189. {*********************************************}
  190. function AbstractRotateAboutLookAt(var Viewer,LookAt,UpVect:tGLPoint;HorAng,VerAng: single): boolean;
  191. {moves the fViewer about fLookAt}
  192. var
  193.   r0, r1: single;
  194.   Pos, View: tGLPoint;
  195. begin
  196.   VerAng:= VerAng*pi180;
  197.   HorAng:= HorAng*pi180;
  198. //assumes up-vector is normalised and maintained perpendicular
  199. //to view-vector.
  200. {subtract origin}
  201.   Pos.x:= Viewer.x - Lookat.x;
  202.   Pos.y:= Viewer.y - Lookat.y;
  203.   Pos.z:= Viewer.z - Lookat.z;
  204.   View:= Pos;      //view_vector
  205. {save radius so move along sphere}
  206.   r0:= sqrt(sqr(Pos.x)+sqr(Pos.y)+sqr(Pos.z));
  207. //y-rotations cause ball to turn in plane of view-vector and up-vector
  208. //so add up-vector to viewer
  209. //Note: dist to move is r * theta (in radians)
  210.   Pos.x:= Pos.x + UpVect.x*VerAng*r0;
  211.   Pos.y:= Pos.y + UpVect.y*VerAng*r0;
  212.   Pos.z:= Pos.z + UpVect.z*VerAng*r0;
  213. //x-rotations cause ball to turn perpendicular to plane of view-vector
  214. //and up-vector so add cross product to viewer
  215. //Note: dist to move is r * theta (in radians) but must divide by
  216. //magnitude of cross-product vectors = r and 1.
  217.   Pos.x:= Pos.x + (View.y*UpVect.z - View.z*UpVect.y)*HorAng;
  218.   Pos.y:= Pos.y + (View.z*UpVect.x - View.x*UpVect.z)*HorAng;
  219.   Pos.z:= Pos.z + (View.x*UpVect.y - View.y*UpVect.x)*HorAng;
  220. {drop point onto sphere}
  221.   r1:= r0/sqrt(sqr(Pos.x)+sqr(Pos.y)+sqr(Pos.z));
  222.   Viewer.X:= LookAt.x + r1*Pos.x;
  223.   Viewer.Y:= LookAt.y + r1*Pos.y;
  224.   Viewer.Z:= LookAt.z + r1*Pos.z;
  225.  
  226. {must also push up-vector in same direction as y-rotation so
  227.  add view vector to upvector and normalise}
  228.   UpVect.x:= UpVect.x - View.x*VerAng/r0;
  229.   UpVect.y:= UpVect.y - View.y*VerAng/r0;
  230.   UpVect.z:= UpVect.z - View.z*VerAng/r0;
  231.   r1:= sqrt(sqr(UpVect.x)+sqr(UpVect.y)+sqr(UpVect.z));
  232.   UpVect.x:= UpVect.x/r1;
  233.   UpVect.y:= UpVect.y/r1;
  234.   UpVect.z:= UpVect.z/r1;
  235.  
  236.   Result:= true;
  237. end;
  238. {*********************************************}
  239. {*********************************************}
  240. constructor TViewFrame.Create;
  241. begin
  242.   inherited Create;
  243.   fScale:= 1;
  244.   with fViewer do begin x:=0; y:=100; z:=0; end;
  245.   with fLookAt do begin x:=0; y:=0; z:=0; end;
  246.   with fUpVect do begin x:=0; y:=0; z:=1; end;
  247.   fRange    := DefaultSize;
  248.   fViewAngle:= DefaultAngle;
  249.   XRadius   := DefaultSize;
  250.   Yradius   := DefaultSize;
  251.   ZRadius   := DefaultSize;
  252.   fPerspective:= false;
  253.   SetUpEyePositions;
  254. end;
  255. {*********************************************}
  256. function TViewFrame.Duplicate: TViewFrame;
  257. var
  258.   p: TViewFrame;
  259. begin
  260.   p:= TViewFrame.Create;
  261.   p.fViewer:=fViewer;
  262.   p.fLookAt:=fLookAt;
  263.   p.fUpVect:= fUpVect;
  264.   p.fLeftEye:=fLeftEye;
  265.   p.fRightEye:=fRightEye;
  266.   p.fOrigin:=fOrigin;
  267.   p.fRange := fRange;
  268.   p.fViewAngle:= fViewAngle;
  269.   p.fScreenZ:= fScreenZ;
  270.   p.fScale:= fScale;
  271.   p.XRadius:= XRadius;
  272.   p.YRadius:= YRadius;
  273.   p.ZRadius:= ZRadius;
  274.   p.fPerspective:= fPerspective;
  275.   Result:= p;
  276. end;
  277. (****************************************)
  278. procedure TViewFrame.SetViewer3s(x,y,z: single);
  279. begin
  280.   fViewer.x:= x;
  281.   fViewer.y:= y;
  282.   fViewer.z:= z;
  283.   fOrigin:=fViewer;
  284.   If Assigned(fHeadLight) then
  285.     fHeadLight.PositionLight(fViewer);
  286.   SetUpEyePositions;
  287. end;
  288. (****************************************)
  289. procedure TViewFrame.SetLookAt3s(x,y,z: single);
  290. begin
  291.   fLookAt.x:= x;
  292.   fLookAt.y:= y;
  293.   fLookAt.z:= z;
  294. end;
  295. (****************************************)
  296. Procedure TViewFrame.SetScale(aVal:Double);
  297.   Var MultVal:Double;
  298.   Begin
  299.     If (fScale=aVal) or (fScale=0) then exit;
  300.     MultVal:=aVal/fScale;
  301.     fRange:= fRange*MultVal;
  302.     XRadius:= XRadius*MultVal;
  303.     Yradius:= YRadius*MultVal;
  304.     ZRadius:= ZRadius*MultVal;
  305.     fScale:=aVal;
  306.     with fViewer do  SetViewer3d(x*MultVal,y*MultVal,z*MultVal);
  307.     with fLookAt do
  308.     begin x:=x*MultVal; y:=y*MultVal; z:=z*MultVal; end;
  309.   end;
  310. (****************************************)
  311. procedure TViewFrame.SetUpVector3s(x,y,z: single);
  312. begin
  313.   fUpVect.x:= x;
  314.   fUpVect.y:= y;
  315.   fUpVect.z:= z;
  316. end;
  317.  
  318.   //jh mod
  319. (****************************************)
  320. procedure TViewFrame.SetViewer3d(x,y,z: Double);
  321. begin
  322.   fViewer.x:= x;
  323.   fViewer.y:= y;
  324.   fViewer.z:= z;
  325.   fOrigin:=fViewer;
  326.   If Assigned(fHeadLight) then
  327.     fHeadLight.PositionLight(fViewer);
  328.   SetUpEyePositions;
  329. end;
  330. (****************************************)
  331. procedure TViewFrame.SetLookAt3d(x,y,z: Double);
  332. begin
  333.   fLookAt.x:= x;
  334.   fLookAt.y:= y;
  335.   fLookAt.z:= z;
  336. end;
  337. (****************************************)
  338.   Function TViewFrame.GetBearing:Double;
  339.     Var B,A:Double;
  340.    Begin
  341.       Result:=0;
  342.       If BearingAndAzimuth(fViewer,fLookAt,B,A) then
  343.        Result:=B;
  344.    end;
  345. (****************************************)
  346.   Function TViewFrame.GetAzimuth:Double;
  347.     Var B,A:Double;
  348.    Begin
  349.       Result:=0;
  350.       If BearingAndAzimuth(fViewer,fLookAt,B,A) then
  351.        Result:=A;
  352.    end;
  353. (****************************************)
  354.   Function TViewFrame.GetAngleFromVertical:Double;
  355.     Var A:Double;
  356.    Begin
  357.       Result:=0;
  358.       If AngleFromVertical(fViewer,fLookAt,A) then
  359.        Result:=A;
  360.    end;
  361. (****************************************)
  362.  Procedure TViewFrame.SetViewPoint(aPt:vViewFrom);
  363.   Begin
  364.     Case aPt of
  365.       vCentrePt:fViewer:=fOrigin;
  366.       vLeftEye:fViewer:=fLeftEye;
  367.       vRightEye:fViewer:=fRightEye;
  368.     end;
  369.   If Assigned(fHeadLight) then
  370.     fHeadLight.PositionLight(fViewer);
  371.   end;
  372. (****************************************)
  373.  Procedure TViewFrame.CopyValuesFrom(aPt:TViewFrame);
  374.     //set the values from the supplied Frame
  375.    Begin
  376.       If not assigned(aPt) then exit;
  377.       fViewer:=aPt.fViewer;
  378.       fLookAt:= aPt.fLookAt;
  379.       fUpVect:= aPt.fUpVect;
  380.       fLeftEye:=aPt.fLeftEye;
  381.       fRightEye:=aPt.fRightEye;
  382.       fOrigin:=aPt.fOrigin;
  383.       fRange := aPt.fRange;
  384.       fViewAngle:= aPt.fViewAngle;
  385.       fScreenZ:= aPt.fScreenZ;
  386.       fScale:= aPt.fScale;
  387.       XRadius:= aPt.XRadius;
  388.       YRadius:= aPt.YRadius;
  389.       ZRadius:= aPt.ZRadius;
  390.       fPerspective:= aPt.fPerspective;
  391.     end;
  392. (****************************************)
  393.  
  394. procedure TViewFrame.SetPerspective(A: boolean);
  395. begin
  396.   fPerspective:= a;
  397. end;
  398. (****************************************)
  399.  
  400. Procedure TViewFrame.SetRange(aVal:Double; AdjustAngle:Boolean);
  401.  // set the range and if adjust then calc a viewangle}
  402.    Var dist,TempVal:Double;
  403.  
  404.    Begin
  405.      If fRange=aVal then exit;
  406.      fRange:=aVal;
  407.      If not adjustAngle then exit;
  408.      dist:=Distance;
  409.      If fRange=0 then fRange:=1;
  410.      TempVal:=fRange/Dist;
  411.      TempVal:=arcTan(TempVal)*(180/Pi);
  412.      fViewangle:=TempVal*2;
  413.      If fViewAngle>180 then fViewAngle:=179;
  414.    end;
  415. {*********************************************}
  416.   Procedure TViewFrame.SetAngle(aVal:Double; AdjustRange:Boolean);
  417.   //Set the view angle and adjust angle if adjustrange=true}
  418.    Begin
  419.  
  420.    end;
  421. {*********************************************}
  422.   Function TViewFrame.Distance:Double;
  423.  // distance between position and lookat
  424.   Begin
  425.      Result:=sqrt(Sqr(Position.X-LookAt.X)+
  426.                   Sqr(Position.y-LookAt.y) +
  427.                   Sqr(Position.z-LookAt.z));
  428.      If abs(Result)<0.0001 then result:=0.0001;
  429.   end;
  430. {*********************************************}
  431.     Function  TViewFrame.MaxViewPrism(aScale:Single):tGLPoint; //Max X,Y znd Z ocvered in viewport
  432.       Begin
  433.         Result.X:=LookAt.X+abs(fRange*aScale);
  434.         Result.Y:=LookAt.Y+abs(fRange*aScale);
  435.         Result.Z:=LookAt.Z+abs(fRange*aScale);
  436.       end;
  437. {*********************************************}
  438.     Function  TViewFrame.MinViewPrism(aScale:Single):tGLPoint; //Min X,Y znd Z ocvered in viewport
  439. // max and min values for view prism
  440.        Begin
  441.         Result.X:=LookAt.X-abs(fRange*aScale);
  442.         Result.Y:=LookAt.Y-abs(fRange*aScale);
  443.         Result.Z:=LookAt.Z-abs(fRange*aScale);
  444.        end;
  445. {*********************************************}
  446.  function TViewFrame.RotateAboutViewer(HorAng,VerAng: single): boolean;
  447.      Begin
  448.        Result:=  AbstractRotateAboutViewer(fViewer,fLookAt,fUpVect,HorAng,VerAng);
  449.      end;
  450. (**********************************************************)
  451. function TViewFrame.RotateAboutLookAt(HorAng,VerAng: single): boolean;
  452.   var TempPt:tGLPoint;
  453.   Begin
  454.     TempPt:=fViewer;
  455.     Result:=AbstractRotateAboutLookAt(TempPt,fLookAt,fUpVect,HorAng,VerAng);
  456.     SetViewer3d(TempPt.X,TempPt.Y,TempPt.Z);
  457.   end;
  458. (**********************************************************)
  459. Procedure TViewFrame.SetUpEyePositions;
  460.   Var TempVec  :tGLPoint;
  461.       {dist,}HAng:Double;
  462.   Begin
  463.     fLeftEye:=fViewer;
  464.     fRightEye:=fViewer;
  465.     HAng:=EyeOffset;
  466.     (*Dist:=Distance;
  467.     HAng:=ArcTan2(EyeOffset,(2*Dist))/pi180;*)
  468.     TempVec:=fUpVect;
  469.     AbstractRotateAboutLookAt(fLeftEye,fLookAt,TempVec,HAng,0);
  470.     TempVec:=fUpVect;
  471.     AbstractRotateAboutLookAt(fRightEye,fLookAt,TempVec,-HAng,0);
  472.   end;
  473. (**********************************************************)
  474.  Procedure TViewFrame.SetViewerPos(aVal:tGLPoint);
  475.    Begin
  476.     SetViewer3d(aVal.X,aVal.Y,aVal.Z);
  477.    end;
  478. (**********************************************************)
  479.   Procedure TViewFrame.SetXRadius(aVal:Double);
  480.      Begin
  481.        If fXRadius=aVal then exit;
  482.        fXRadius:=aVal;
  483.        If fXRadius<MinCubeSize then fXRadius:=MinCubeSize;
  484.      end;
  485. (**********************************************************)
  486.   Procedure TViewFrame.SetYRadius(aVal:Double);
  487.      Begin
  488.        If fYRadius=aVal then exit;
  489.        fYRadius:=aVal;
  490.        If fYRadius<MinCubeSize then fYRadius:=MinCubeSize;
  491.      end;
  492. (**********************************************************)
  493.   Procedure TViewFrame.SetZRadius(aVal:Double);
  494.      Begin
  495.        If fZRadius=aVal then exit;
  496.        fZRadius:=aVal;
  497.        If fZRadius<MinCubeSize then fZRadius:=MinCubeSize;
  498.      end;
  499. (**********************************************************)
  500.  
  501. function TViewFrame.RotateUpVector(Ang: single): boolean;
  502. {rotate view about line from Viewer to LookAt}
  503. var
  504.   r1: single;
  505.   View: tGLPoint;
  506.  
  507. begin
  508. //assumes up-vector is normalised and maintained perpendicular
  509. //to view-vector.
  510. {subtract origin}
  511.   View.x:= fViewer.x - fLookat.x;
  512.   View.y:= fViewer.y - fLookat.y;
  513.   View.z:= fViewer.z - fLookat.z;      //view_vector
  514. {convert to radians, divide by radius}
  515.   Ang:= Ang*pi180/sqrt(sqr(View.x)+sqr(View.y)+sqr(View.z));
  516. //rotation is perpendicular to plane of view-vector and up-vector
  517. //so add cross product to up-vector
  518. //Note: dist to move is r * theta (in radians) but must divide by
  519. //magnitude of cross-product vectors = r and 1.
  520.   fUpVect.x:= fUpVect.x + (View.y*fUpVect.z - View.z*fUpVect.y)*Ang;
  521.   fUpVect.y:= fUpVect.y + (View.z*fUpVect.x - View.x*fUpVect.z)*Ang;
  522.   fUpVect.z:= fUpVect.z + (View.x*fUpVect.y - View.y*fUpVect.x)*Ang;
  523.   r1:= 1/sqrt(sqr(fUpVect.x)+sqr(fUpVect.y)+sqr(fUpVect.z));
  524.   fUpVect.x:= fUpVect.x*r1;
  525.   fUpVect.y:= fUpVect.y*r1;
  526.   fUpVect.z:= fUpVect.z*r1;
  527.   Result:= true;
  528. end;
  529. (************************************************************)
  530.  Function TViewFrame.ShiftLookAt(aDist:Double):Boolean;
  531.     // shift the lookat away from the viewer by the supplied dist
  532. var
  533.   s, xDist, yDist, zDist: single;
  534. begin
  535.   s:= DistanceBetween(fViewer,fLookAt);
  536.   Result:= s<>0;
  537.   if Result then
  538.    begin
  539.     xDist:= (fLookAt.x-fViewer.x)*aDist/s;
  540.     yDist:= (fLookAt.y-fViewer.y)*aDist/s;
  541.     zDist:= (fLookAt.z-fViewer.z)*aDist/s;
  542.  
  543.     with fLookAt do
  544.     begin
  545.       x:=x+xDist;  y:=y+yDist;  z:=z+zDist;
  546.     end;
  547.   end;
  548.   Result:= true;
  549. end;
  550. (************************************************************)
  551. function TViewFrame.AdvanceToLookAt(Dist: single): boolean;   {and rotate HorAng as well?}
  552. {Move fViewer and fLookAt Dist in direction of joining vector.
  553.  Dist can be pos or neg.}
  554. var
  555.   s, xDist, yDist, zDist: single;
  556. begin
  557.   s:= DistanceBetween(fViewer,fLookAt);
  558.   Result:= s<>0;
  559.   if Result then
  560.    begin
  561.     xDist:= (fLookAt.x-fViewer.x)*Dist/s;
  562.     yDist:= (fLookAt.y-fViewer.y)*Dist/s;
  563.     zDist:= (fLookAt.z-fViewer.z)*Dist/s;
  564.  
  565.     with fViewer do
  566.      SetViewer3d(x+xDist,y+yDist,z+zDist);
  567.  
  568.     with fLookAt do
  569.     begin
  570.       x:=x+xDist;  y:=y+yDist;  z:=z+zDist;
  571.     end;
  572.   end;
  573.   Result:= true;
  574. end;
  575.  
  576. procedure TViewFrame.MovePosition(DeltaX,DeltaY,DeltaZ: single);
  577. begin
  578.   with fViewer do
  579.      SetViewer3d(x+DeltaX,y+DeltaY,z+DeltaZ);
  580. end;
  581.  
  582. procedure TViewFrame.MoveFrame(DeltaX,DeltaY,DeltaZ: single);
  583. begin
  584.   with fViewer do
  585.      SetViewer3d(x+DeltaX,y+DeltaY,z+DeltaZ);
  586.  
  587.   With fLookAt do
  588.   Begin
  589.     X:=X+DeltaX;
  590.     Y:=Y+DeltaY;
  591.     Z:=Z+DeltaZ;
  592.   end;
  593. end;
  594.  
  595. function TViewFrame.FlyBy(Speed,RollAng,PitchAng: single): boolean;
  596. begin
  597.   RotateAboutViewer(RollAng,-PitchAng);
  598.   RotateUpVector(-RollAng);
  599.   AdvanceToLookAt(Speed);
  600.   Result:= true;
  601. end;
  602.  
  603. end.
  604.